// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0

/// Basic information on a known component
export struct ComponentItem {
    name: string,
    index: int,
    defined-at: string,
    pretty-location: string,
    is-user-defined: bool,
    is-currently-shown: bool,
    is-exported: bool,
}

/// A `category` with a lost of `ComponentItem`s that belong into it.
///
/// File url is either an empty string or a URL to some document
export struct ComponentListItem {
    category: string,
    file_url: string,
    components: [ComponentItem]
}

/// Some `Diagnostics` as raised by the compiler
export enum DiagnosticSummary {
    NothingDetected,
    Warnings,
    Errors,
}

/// What kind of layout we are working with
export enum LayoutKind {
    None,
    Horizontal,
    Vertical,
    Grid,
}

/// A rectangular region that is selected
struct SelectionRectangle {
    x: length,
    y: length,
    width: length,
    height: length,
}

/// A `Selection`
export struct Selection {
    geometry: SelectionRectangle,
    layout-data: LayoutKind,
    is-interactive: bool,
    is-primary: bool,
    is-moveable: bool,
    is-resizable: bool,
}

/// A mark showing where an element will show up when dropped into the current location
export struct DropMark {
    x1: length,
    y1: length,
    x2: length,
    y2: length,
}

export struct SelectionStackFrame {
    width: percent,
    height: percent,
    x: percent,
    y: percent,
    is-in-root-component: bool,
    is-layout: bool,
    is-interactive: bool,
    is-selected: bool,
    type-name: string,
    file-name: string,
    element-path: string,
    element-offset: int,
    id: string,
}

export enum SelectionStackFilter {
    Nothing,
    Layouts,
    Interactive,
    Others,
    LayoutsAndInteractive,
    LayoutsAndOthers,
    InteractiveAndOthers,
    Everything,
}

/// A Range in a source
export struct Range {
    start: int,
    end: int,
}

export struct ColorData {
    r: int,
    g: int,
    b: int,
    a: int,
    text: string,
    short-text: string,
}

export enum PropertyValueKind {
    boolean,
    brush,
    code,
    color,
    enum,
    float,
    integer,
    string,
}

export enum BrushKind {
    solid,
    linear,
    radial,
}

export struct GradientStop {
    position: float, // between 0 and 1!
    color: color,
}

/// Data about the property value for use in "simple" mode
export struct PropertyValue {
    display-string: string, // ALLWAYS, its a string description of what is there
    value-bool: bool, // boolean
    is-translatable: bool, // string
    kind: PropertyValueKind,
    brush-kind: BrushKind, // brush
    gradient-stops: [GradientStop], // brush
    value-brush: brush, // brush, color
    value-float: float, // float, brush (angle)
    value-int: int, // integer, enum/float (current index into visual_items)
    default-selection: int, // enum/float (default index into visual_items)
    value-string: string, // enum (name), string, brush (palette name or empty)
    visual-items: [string], // enum (enum members), float (units)
    tr-context: string, // string
    tr-plural: string, // string
    tr-plural-expression: string, // string
    code: string, // ALWAYS, empty if property is not explicitly defined
    accessor-path: string, // set for struct members and such
    was-edited: bool, // Used by preview dataonly!
    edited-value: string, // Used in preview dataonly!
}

export struct PropertyValueTable {
    is-array: bool,
    headers: [string],
    values: [[PropertyValue]],
}

/// Important Ranges in the property definition
///
/// The URL and version is the same as in the Element it belongs to
export struct PropertyDefinition {
    definition-range: Range,
    selection-range: Range,
    expression-range: Range,
    expression-value: string,
}

/// The Property Declaration
export struct PropertyDeclaration {
    defined-at: PropertyDefinition,

    source-path: string,
    source-version: int,
    range: Range,
}

/// Information on one Property
export struct PropertyInformation {
    name: string,
    type-name: string,
    value: PropertyValue,
    display-priority: int,
}

/// Grouping for properties
export struct PropertyGroup {
    group-name: string,
    properties: [PropertyInformation],
}

export enum PreviewDataKind {
    Value,
    Json,
    Table,
}

export struct PreviewData {
    name: string,
    has-getter: bool,
    has-setter: bool,
    kind: PreviewDataKind,
}

/// Information on exported components and their properties
export struct PropertyContainer {
    container-name: string,
    container-id: string,
    properties: [PreviewData],
}

/// Information on an Element a Property belongs to
export struct ElementInformation {
    id: string,
    type-name: string,
    source-uri: string,
    source-version: int,
    range: Range,
}

export struct PaletteEntry {
    name: string,
    value: PropertyValue,
}

export global Api {
    // # Properties
    // ## General preview state:
    // experimental features are available
    in property <bool> experimental: false;
    // enable editing mode
    in property <bool> show-preview-ui: true;
    // std-widgets are used (=> show style dropdown)
    in-out property <bool> uses-widgets;
    in-out property <bool> always-on-top;
    in property <bool> focus-previewed-element;

    // ## Component Data for ComponentList:
    // All the components
    in property <[ComponentListItem]> known-components;
    // The component currently viewed
    out property <ComponentItem> visible-component;

    // ## Kinds of diagnostics seen in the last compiler run
    in property <DiagnosticSummary> diagnostic-summary;
    // status message text
    in property <string> status-text;

    // ## Style:
    // All the known styles
    in property <[string]> known-styles;
    // The current style
    in-out property <string> current-style;
    // control, but command on macOS
    in-out property <string> control-key-name: "control";

    // ## Drawing Area
    // Borders around things
    in property <[Selection]> selections;
    in-out property <DropMark> drop-mark;
    // The actual preview
    in property <component-factory> preview-area;

    // set to true to resize
    in property <bool> resize-to-preferred-size: false;

    // ## Palette data:
    in-out property <[PaletteEntry]> palettes;
    in-out property <[color]> recent-colors;

    // ## Property Editor
    in-out property <ElementInformation> current-element;
    in-out property <[PropertyGroup]> properties: [
        {
            group-name: "Geometry",
            properties: [
                {
                    name: "width",
                    type-name: "length",
                    value: {
                        kind: PropertyValueKind.float,
                        value-float: 100,
                        visual-items: ["px", "cm", "mm", "in", "pt", "phx"],
                    }
                },
                {
                    name: "height",
                    type-name: "length",
                    value: {
                        kind: PropertyValueKind.float,
                        value-float: 200,
                        visual-items: ["px", "cm", "mm", "in", "pt", "phx"],
                    }
                },
                {
                    name: "z",
                    type-name: "float",
                    value: {
                        kind: PropertyValueKind.float,
                        value-float: 10,
                    }
                },
                {
                    name: "combobox",
                    type-name: "string",
                    value: {
                        kind: PropertyValueKind.enum,
                        value-int: 1,
                        default-selection: 0,
                        visual-items: ["one", "twenty two", "one hundred", "infinite"],
                    }
                },
            ]
        },
        {
            group-name: "Button",
            properties: [
                {
                    name: "text",
                    type-name: "string",
                    value: {
                        is-translatable: true,
                        kind: PropertyValueKind.string,
                    }
                },
                {
                    name: "checkable",
                    type-name: "bool",
                    value: {
                        kind: PropertyValueKind.boolean,
                    }
                },
                {
                    name: "icon",
                    type-name: "image",
                    value: {
                        kind: PropertyValueKind.code,
                    }
                },
                {
                    name: "brush",
                    type-name: "brush",
                    value: {
                        kind: PropertyValueKind.brush,
                        value-brush: Colors.green,
                        value-string: "#00ff00"
                    },
                },
                {
                    name: "text-between",
                    type-name: "string",
                    value: {
                        is-translatable: true,
                        kind: PropertyValueKind.string,
                    }
                },
                {
                    name: "color",
                    type-name: "color",
                    value: {
                        kind: PropertyValueKind.color,
                        value-brush: Colors.green,
                        value-string: "#00ff00"
                    },
                },

                {
                    name: "a-really-long-named-attribute",
                    type-name: "float",
                    value: {
                        kind: PropertyValueKind.float,
                        value-float: 10,
                    }
                },
                {
                    name: "bar",
                    type-name: "float",
                    value: {
                        kind: PropertyValueKind.code,
                        value-float: 10.5,
                        code: 10/2,
                    }
                },
                {
                    name: "baz",
                    type-name: "float",
                    value: {
                        kind: PropertyValueKind.code,
                        value-float: 10.5,
                        code: "",
                    }
                }

            ]
        },        {
            group-name: "Other",
            properties: [
                {
                    name: "text",
                    type-name: "string",
                    value: {
                        is-translatable: true,
                        kind: PropertyValueKind.string,
                    }
                },
                {
                    name: "checkable",
                    type-name: "bool",
                    value: {
                        kind: PropertyValueKind.boolean,
                    }
                },
                {
                    name: "icon",
                    type-name: "image",
                    value: {
                        kind: PropertyValueKind.code,
                    }
                },
                {
                    name: "color",
                    type-name: "brush",
                    value: {
                        kind: PropertyValueKind.brush,
                        value-brush: Colors.magenta,
                        value-string: "#ff00ff"
                    },
                },
                {
                    name: "a-really-long-named-attribute",
                    type-name: "float",
                    value: {
                        kind: PropertyValueKind.float,
                        value-float: 10,
                    }
                },
                {
                    name: "bar",
                    type-name: "float",
                    value: {
                        kind: PropertyValueKind.code,
                        value-float: 10.5,
                        code: 10/2,
                    }
                },
                {
                    name: "baz",
                    type-name: "float",
                    value: {
                        kind: PropertyValueKind.code,
                        value-float: 10.5,
                        code: "",
                    }
                }

            ]
        }

    ];

    // ## preview data

    in-out property <[PropertyContainer]> preview-data;

    // # Callbacks

    // ## Custom conversion functions:
    pure callback string-is-color(string) -> bool;
    pure callback string-to-color(string) -> color;
    pure callback color-to-data(color) -> ColorData;
    pure callback rgba_to_color(r: int, g: int, b: int, a: int) -> color;

    // ## Style:
    callback style-changed();

    // ## Component life-cycle:

    // Create a new component
    callback add-new-component();

    // Add an existing component
    pure callback can-drop(component-index: int, x: length, y: length, on-drop-area: bool) -> bool;
    callback drop(component-index: int, x: length, y: length);

    callback rename-component(old-name: string, defined-at: string, new-name: string);

    callback selected-element-can-move-to(x: length, y: length, mouse-x: length, mouse-y: length) -> bool;
    callback selected-element-move(x: length, y: length, mouse-x: length, mouse-y: length);

    callback selected-element-resize(x: length, y: length, width: length, height: length);

    callback selected-element-delete();

    // ## Element selection:
    callback selection-stack-at(x: length, y: length) -> [SelectionStackFrame];
    pure callback filter-sort-selection-stack(model: [SelectionStackFrame], filter_text: string, filter: SelectionStackFilter) -> [SelectionStackFrame];
    pure callback find-selected-selection-stack-frame([SelectionStackFrame]) -> SelectionStackFrame;
    callback select-element(file: string, offset: int, x: length, y: length);

    callback select-at(x: length, y: length, enter-component: bool);
    callback select-behind(x: length, y: length, enter-component: bool, reverse: bool);
    callback reselect();
    callback unselect();

    // ## Change Editor:

    // Show a component in the editor
    callback show-component(name: string, url: string);
    // Show a position consisting of `line` and `column` in a `file` in the editor
    callback show-document(file: string, line: int, column: int);
    // Show a position consisting of `line` and `column` in a `file` in the editor
    callback show-document-offset-range(url: string, start_offset: int, end_offset: int, take-focus: bool);

    // ## Drawing Area
    // Preview some other component
    callback show-preview-for(name: string, url: string);
    callback reload-preview();

    // ## Property Editor
    pure callback test-code-binding(element-url: string, element-version: int, element-offset: int, property-name: string, property-value: string) -> bool;
    pure callback set-code-binding(element-url: string, element-version: int, element-offset: int, property-name: string, property-value: string);
    pure callback set-color-binding(element-url: string, element-version: int, element-offset: int, property-name: string, property-value: color);

    pure callback string-to-code(value: string, is_translatable: bool, tr_context: string, tr_plural: string, tr_plural_expression: string) -> string;

    pure callback as-slint-brush(kind: BrushKind, angle: float, color: color, stops: [GradientStop]) -> string;

    // ## preview data
    pure callback get-property-value(component: string, name: string) -> PropertyValue;
    pure callback get-property-value-table(component: string, name: string) -> PropertyValueTable;
    pure callback set-property-value-table(component: string, name: string, table: [[PropertyValue]], is-array: bool) -> string;

    pure callback insert-row-into-value-table(table: PropertyValueTable, insert-before: int);
    pure callback remove-row-from-value-table(table: PropertyValueTable, remove-row: int);

    pure callback set-json-preview-data(component: string, name: string, json-value: string, send-telemetry: bool) -> string;

    pure callback as-json-brush(kind: BrushKind, angle: float, color: color, stops: [GradientStop]) -> string;

    pure callback add-gradient-stop(stops: [GradientStop], value: GradientStop) -> int;
    pure callback remove-gradient-stop(stops: [GradientStop], row: int);
    // returns the new index of the gradient stop in the sorted list of GradientStops
    pure callback move-gradient-stop(stops: [GradientStop], row: int, new_position: float) -> int;
    pure callback suggest-gradient-stop-at-row(stops: [GradientStop], row: int) -> GradientStop;
    pure callback suggest-gradient-stop-at-position(stops: [GradientStop], position: float) -> GradientStop;
    pure callback clone-gradient-stops(stops: [GradientStop]) -> [GradientStop];

    pure callback create-brush(kind: BrushKind, angle: float, color: color, stops: [GradientStop]) -> brush;

    // Get the property declaration/definition ranges
    callback property-declaration-ranges(property-name: string) -> PropertyDeclaration;

    // Palettes:
    pure callback filter-palettes(palettes: [PaletteEntry], pattern: string) -> [PaletteEntry];
    callback add-recent-color(color);
    pure callback is-svg-color(code: string) -> bool;
}
